package gwtide.wizards;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import org.eclipse.core.internal.resources.ProjectDescription;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWizard;

/**
 * @author DChen dwchen1999@gmail.com
 */

public class NewProject extends Wizard implements INewWizard {
	private NewProjectPage page;

	private ISelection selection;

	/**
	 * Constructor for SampleNewWizard.
	 */
	public NewProject() {
		super();
		setNeedsProgressMonitor(true);
	}

	/**
	 * Adding the page to the wizard.
	 */

	public void addPages() {
		page = new NewProjectPage(selection);
		addPage(page);
	}

	/**
	 * This method is called when 'Finish' button is pressed in the wizard. We
	 * will create an operation and run it using wizard as execution context.
	 */
	public boolean performFinish() {
		final String prjName = page.getPrjName();
		final String gwtHome = page.getGwtHome();
		final String prjLc = page.getPrjLc();

		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor)
					throws InvocationTargetException {
				try {
					doFinish(prjName, prjLc, gwtHome, monitor);
				} catch (CoreException e) {
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};
		try {
			getContainer().run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(), "Error", realException
					.getMessage());
			return false;
		}
		return true;
	}

	/**
	 */
	private void doFinish(String prjName, String prjLc, String gwtHome,
			IProgressMonitor monitor) throws CoreException {
		// 1 create project
		// 2 add gwt jars to class path
		// 3 create source folder, test folder, build folder
		// 4 set class path

		monitor.beginTask("Creating project" + prjName, 2);
		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
		IJavaModel jModel = JavaCore.create(root);

		IProject project = root.getProject(prjName);
		IProjectDescription des = new ProjectDescription();
		des.setName(prjName);
		des.setLocation(new Path(prjLc));
		des.setNatureIds(new String[] { JavaCore.NATURE_ID });
		
		ICommand command = des.newCommand();
		command.setBuilderName(JavaCore.BUILDER_ID);
		
		des.setBuildSpec(new ICommand[]{command});
		if (!project.exists()) {
			project.create(des, monitor);
		}
		IJavaProject javaProject = JavaCore.create(project);
		project.open(monitor);

		IFolder srcFolder = project.getFolder("src");
		if (!srcFolder.exists()) {
			srcFolder.create(true, true, monitor);
		}

		IFolder buildFolder = project.getFolder("build");
		if (!buildFolder.exists()) {
			buildFolder.create(true, true, monitor);
		}

		IFolder testFolder = project.getFolder("test");
		if (!testFolder.exists()) {
			testFolder.create(true, true, monitor);
		}

		IFolder webInf = project.getFolder("WEB-INF");
		if (!webInf.exists()) {
			webInf.create(true, true, monitor);
		}
		try {
			setClassEntries(javaProject, gwtHome, monitor);
		} catch (Exception e) {
			e.printStackTrace();// TODO
		}
	}

	private void setClassEntries(IJavaProject javaProject, String gwtHome,
			IProgressMonitor monitor) throws Exception {
		String gwtUserLib = gwtHome + "/gwt-user.jar";
		ArrayList<IClasspathEntry> classEntryList = new ArrayList<IClasspathEntry>();
		IClasspathEntry gwtUserLibEntry = JavaCore.newLibraryEntry(new Path(
				gwtUserLib), null, null);
		classEntryList.add(gwtUserLibEntry);

		String gwtServletLib = gwtHome + "/gwt-servlet.jar";
		IClasspathEntry gwtServletLibEntry = JavaCore.newLibraryEntry(new Path(
				gwtServletLib), null, null);
		classEntryList.add(gwtServletLibEntry);

		String gwtDevLib = gwtHome + "/gwt-dev-windows.jar";
		IClasspathEntry gwtDevLibEntry = JavaCore.newLibraryEntry(new Path(
				gwtDevLib), null, null);
		classEntryList.add(gwtDevLibEntry);

		IPath prjLc = javaProject.getPath();
		IClasspathEntry src = JavaCore.newSourceEntry(new Path(prjLc + "/src"));
		classEntryList.add(src);

		IClasspathEntry test = JavaCore
				.newSourceEntry(new Path(prjLc + "/test"));
		classEntryList.add(test);

		IClasspathEntry con = JavaCore.newContainerEntry(new Path(
				"org.eclipse.jdt.launching.JRE_CONTAINER"), true);
		classEntryList.add(con);

		javaProject.setRawClasspath(classEntryList
				.toArray(new IClasspathEntry[] {}), new Path(prjLc + "/build"),
				monitor);
		
	}

	/**
	 * We will initialize file contents with a sample text.
	 */

	private InputStream openContentStream() {
		String contents = "This is the initial file contents for *.mpe file that should be word-sorted in the Preview page of the multi-page editor";
		return new ByteArrayInputStream(contents.getBytes());
	}

	private void throwCoreException(String message) throws CoreException {
		IStatus status = new Status(IStatus.ERROR, "gwtIDE", IStatus.OK,
				message, null);
		throw new CoreException(status);
	}

	/**
	 * We will accept the selection in the workbench to see if we can initialize
	 * from it.
	 * 
	 * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.selection = selection;
	}
}